package com.lmk.ms.common.obs.service.impl;

import cn.hutool.core.io.unit.DataSizeUtil;
import com.lmk.ms.common.obs.config.MinIoProperties;
import com.lmk.ms.common.obs.service.ObsFileService;
import com.lmk.ms.common.vo.obs.OssFileVO;
import io.minio.*;
import io.minio.PutObjectArgs.Builder;
import io.minio.http.Method;
import jakarta.annotation.PostConstruct;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;

/**
 * MinIo 服务实现
 * @author laomake@hotmail.com
 * @version 1.0
 * @date 2022-07-05
 */
@Slf4j
public class MinIoFileServiceImpl implements ObsFileService {

    @Autowired
    MinIoProperties minIoProperties;

    private MinioClient minioClient;

    /** 外链地址模板：带端口 */
    String urlTemplate = "%s/%s/%s";

    /** 外链地址模板：无端口 */
    String urlTemplateWithPort = "%s:%d/%s/%s";

    @PostConstruct
    public void init(){
        try {
            Integer port = minIoProperties.getPort();
            if(port == null){
                port = 80; // 默认80端口
            }
            minioClient = MinioClient.builder().endpoint(minIoProperties.getEndpoint(), port, minIoProperties.getSecure()).credentials(minIoProperties.getAccessKey(), minIoProperties.getSecretKey()).build();
            if (!minioClient.bucketExists(BucketExistsArgs.builder().bucket(minIoProperties.getBucket()).build())) {
                minioClient.makeBucket(MakeBucketArgs.builder().bucket(minIoProperties.getBucket()).build());
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 上传 MultipartFile
     * @param multipartFile
     * @return
     */
    public OssFileVO upload(MultipartFile multipartFile) {
        String directory = minIoProperties.getDirectory();

        try (InputStream inputStream = multipartFile.getInputStream()) {
            String originalFileName = multipartFile.getOriginalFilename();
            String fileName = generateFileName(originalFileName);
            long fileSize = multipartFile.getSize();

            Builder builder = getBuilder(directory + fileName, inputStream);
            minioClient.putObject(builder.contentType(multipartFile.getContentType()).build());

            return new OssFileVO(originalFileName, getUrl(fileName), fileSize, DataSizeUtil.format(fileSize));
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    @Override
    public OssFileVO upload(String fileName, InputStream is){
        try{
            Builder builder = getBuilder(fileName, is);
            minioClient.putObject(builder.build());
        }catch (Exception e){
            log.error("文件上传失败：", e);
        }
        return new OssFileVO(fileName, getUrl(fileName));
    }

    /**
     * 删除文件
     * @param fileName 文件唯一标识符
     */
    @Override
    public void remove(String fileName) {
        try {
            minioClient.removeObject(RemoveObjectArgs.builder().bucket(minIoProperties.getBucket()).object(fileName).build());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 下载
     * @param fileName
     * @param response
     */
    @Override
    public void download(String fileName, HttpServletResponse response) {
        try (GetObjectResponse getObjectResponse = minioClient
                .getObject(GetObjectArgs.builder().bucket(minIoProperties.getBucket()).object(fileName).build());) {
            response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
            response.setContentType("application/force-download");
            response.setCharacterEncoding("UTF-8");
            IOUtils.copy(getObjectResponse, response.getOutputStream());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * 获取直链地址
     * @param fileName 文件名
     * @return
     */
    @Override
    public String getUrl(String fileName) {
        Integer port = minIoProperties.getPort();
        if(port == null){
            return String.format(urlTemplate, minIoProperties.getEndpoint(), minIoProperties.getBucket(), minIoProperties.getDirectory() + fileName);
        } else {
            return String.format(urlTemplateWithPort, minIoProperties.getEndpoint(), minIoProperties.getPort(), minIoProperties.getBucket(), minIoProperties.getDirectory() + fileName);
        }

    }

    /**
     * 获取临时地址
     * @param fileName   文件名
     * @param expiry 过期时间 单位:秒, 默认过期时间: 7天
     * @return
     */
    @Override
    public String getTemporaryUrl(String fileName, int expiry) {
        try {
            return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().method(Method.GET)// 只能通过get请求访问
                    .bucket(minIoProperties.getBucket()).object(fileName).expiry(expiry).build());
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 获取builder
     * @param inputStream
     * @return
     */
    private Builder getBuilder(String fileName, InputStream inputStream) {
        try {
            return PutObjectArgs.builder().object(fileName).bucket(minIoProperties.getBucket()).stream(inputStream, inputStream.available(), -1);
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }
}
